/*
 * Copyright 2009 Johnson Consulting Services
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * 
 */
package com.johnsoncs.gwt.widgets.server.export;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportException;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportRequest;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportRuntimeException;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportService;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportStatus;
import com.johnsoncs.gwt.widgets.client.dynamictable.export.MappedExportRequest;
import com.johnsoncs.gwt.widgets.server.util.IoUtils;

/**
 * @author wilj
 *
 */
public abstract class ExportServlet<T> extends RemoteServiceServlet implements ExportService<T> {
	// TODO re-enable SLF4J after switch over to GWT 2.0 due to issue #3496
	// private static final Logger logger = LoggerFactory.getLogger(ExportServlet.class);
	private static final Logger logger = Logger.getLogger(ExportServlet.class.getName());
	private static final long serialVersionUID = 1L;

	private final ThreadLocal<HttpServletRequest> exportThreadLocalRequest = new ThreadLocal<HttpServletRequest>();
	private final ThreadLocal<HttpServletResponse> exportThreadLocalResponse = new ThreadLocal<HttpServletResponse>();

	/* (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	@Override
	protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException,
			IOException {
		exportThreadLocalRequest.set(req);
		exportThreadLocalResponse.set(resp);
		final String exportId = req.getParameter("exportId");
		final ExportStatusProxy proxy = getExportStatusProxy();
		final ExportStatus status = proxy.getExportStatus(exportId);
		final ExportStorage storage = getExportStorage();

		try {
			final InputStream in = storage.getExportResult(status.getFileName());
			if (in == null) {
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
			} else {
				resp.setContentType(status.getMimeType());
				if (status.isAttachment()) {
					resp.setHeader("Content-disposition", "attachment; filename=" + status.getFileName());
				}
				final OutputStream out = resp.getOutputStream();
				IoUtils.redirect(in, out);
				out.close();
			}
		} catch (final Exception e) {
			// TODO re-enable SLF4J after switch over to GWT 2.0 due to issue #3496
			//logger.error("Error retrieving export results", e);
			logger.log(Level.SEVERE, "Error retrieving export results", e);
			throw new ServletException("Error retrieving export results for exportId: " + exportId, e);
		}
	}

	/* (non-Javadoc)
	 * @see com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportService#export(com.johnsoncs.gwt.widgets.client.dynamictable.export.ExportRequest)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public ExportStatus export(final ExportRequest<T> request) throws ExportException {
		try {
			final ExportFormat<T> format = getInstance(request.getExportFormatClassName());
			if (format instanceof MappedExportFormat && request instanceof MappedExportRequest) {
				final RowMapper<T> mapper = getInstance(((MappedExportRequest) request).getRowMapperClassName());
				((MappedExportFormat) format).setRowMapper(mapper);
			}
			return ExportManager.export(request, format, getExportModel(request), getExportStorage(),
					getExportStatusProxy());
		} catch (final Exception e) {
			// TODO re-enable SLF4J after switch over to GWT 2.0 due to issue #3496
			//logger.error("Error processing export request", e);
			logger.log(Level.SEVERE, "Error processing export request", e);
			if (e instanceof ExportException) {
				throw (ExportException) e;
			} else {
				throw new ExportRuntimeException(e);
			}
		}
	}

	public abstract ExportModel<T> getExportModel(ExportRequest<T> request);

	public abstract ExportStatusProxy getExportStatusProxy();

	public abstract ExportStorage getExportStorage();

	/**
	 * @return the exportThreadLocalRequest
	 */
	protected HttpServletRequest getExportThreadLocalRequest() {
		HttpServletRequest result = exportThreadLocalRequest.get();
		if (result == null) {
			result = getThreadLocalRequest();
		}
		return result;
	}

	/**
	 * @return the exportThreadLocalResponse
	 */
	protected HttpServletResponse getExportThreadLocalResponse() {
		HttpServletResponse result = exportThreadLocalResponse.get();
		if (result == null) {
			result = getThreadLocalResponse();
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	protected <RequestedClassType> RequestedClassType getInstance(final String className) throws ExportException {
		try {
			return (RequestedClassType) Class.forName(className).newInstance();
		} catch (final Exception e) {
			throw new ExportException("Unabled to instantiate " + className, e);
		}
	}

}
